package com.bzg.spring.application;

import com.bzg.spring.annotation.MyComponent;
import com.bzg.spring.annotation.MyComponentScan;
import com.bzg.spring.annotation.MyLazy;
import com.bzg.spring.annotation.MyScope;
import com.bzg.spring.myenum.Scope;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基于configClass的applicationContext
 * */
public class MyAnnotationApplicationContext implements BeanFactory,BeanDefinitionRegistrar{

	private BeanFactory beanFactory;

	private Class<?> configClass;

	public MyAnnotationApplicationContext(Class configClass) {
		this.configClass = configClass;
		beanFactory = new MyBeanFactory();
		scanComponent();

		Map<String, MyBeanDefinition> beanDefinition = getBeanDefinition();
		// 先初始化所有后置处理器
		List<String> beanPostProcessor = instanceBeanPostProcessor();
		beanDefinition.forEach((String k,MyBeanDefinition v) -> {
			if(!v.isLazy() && v.getScope().equals(Scope.SINGLETON.getValue()) && !v.getBeanClass().isInterface()
					&& !Modifier.isAbstract(v.getBeanClass().getModifiers()) && !beanPostProcessor.contains(k)) {
				Object bean = getBean(k);
				if(bean != null) {
					registrarBean(k,bean);
				}
			}
		});
	}

	private List<String> instanceBeanPostProcessor(){
		Map<String, Object> beans = getBeans(MyBeanPostProcessor.class);
		List<String> beanNames = new ArrayList(beans.keySet());
		Map<String, MyBeanDefinition> beanDefinition = getBeanDefinition();
		beanDefinition.forEach((String k,MyBeanDefinition v) -> {
			if(!v.isLazy() && v.getScope().equals(Scope.SINGLETON.getValue()) && !v.getBeanClass().isInterface()
					&& !Modifier.isAbstract(v.getBeanClass().getModifiers()) && MyBeanPostProcessor.class.isAssignableFrom(v.getBeanClass())) {
				Object bean = getBean(k);
				if(bean != null) {
					registrarBean(k,bean);
				}
				beanNames.add(k);
			}
		});
		return beanNames;
	}

	private void scanComponent(){
		MyComponentScan annotation = configClass.getAnnotation(MyComponentScan.class);
        if(annotation != null) {
			String[] values = annotation.value();
			ClassLoader classLoader = configClass.getClassLoader();
			for (int i = 0; i < values.length ; i++) {
				String value = values[i];
				String path = value.replaceAll("\\.", "/");
				URL resource = classLoader.getResource(path);
				if(resource != null) {
					registrarComponent(new File(resource.getFile()));
				}
			}
		}
	}

	// 注册beanDefinition
	private void registrarComponent(File file) {
		if(file.isDirectory()) {
			File[] files = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				file = files[i];
				if(file.getAbsolutePath().endsWith(".class")) {
					registrarComponent(file);
				}
			}
		}else {
			String packagePath = parsePackagePath(file.getAbsolutePath());
			if(packagePath != null) {
				try {
					Class<?> clazz = Class.forName(packagePath);
					MyComponent annotation = clazz.getAnnotation(MyComponent.class);
					if(annotation != null) {
						MyBeanDefinition beanDefinition = new MyBeanDefinition();
						String beanName = annotation.value();
						if(beanName.endsWith("")) {
							beanName = generateBeanName(clazz);
						}
						beanDefinition.setBeanClass(clazz);
						beanDefinition.setBeanName(beanName);
						MyScope scope = clazz.getAnnotation(MyScope.class);
						if(scope != null) {
							beanDefinition.setScope(scope.value().getValue());
						}

						MyLazy lazy = clazz.getAnnotation(MyLazy.class);
						if(lazy != null) {
							beanDefinition.setLazy(true);
						}

						registrarBeanDefinition(beanName,beanDefinition);
					}
				}catch (Exception e){}
			}
		}
	}
    // 等同于 Introspector.decapitalize(beanClass.getName());本质就是以开头为小写的类名
	private String generateBeanName(Class<?> beanClass){
		String simpleName = beanClass.getSimpleName();
		char c = simpleName.charAt(0);
		String s = String.valueOf(c).toLowerCase();
		return s + simpleName.substring(1);
	}

	private String parsePackagePath(String filePath) {
		int index;
		if (filePath != null && (index = filePath.lastIndexOf("classes")) > -1) {
			return filePath.substring(index + 8).replaceAll("/", ".").replaceAll("\\\\", ".")
					.replace(".class", "");
		}
		return null;
	}

	@Override
	public void registrarBeanDefinition(String beanName, MyBeanDefinition beanDefinition) {
		if(beanFactory instanceof BeanDefinitionRegistrar) {
			((BeanDefinitionRegistrar)beanFactory).registrarBeanDefinition(beanName,beanDefinition);
		}
	}

	@Override
	public Map<String, MyBeanDefinition> getBeanDefinition() {
		if(beanFactory instanceof BeanDefinitionRegistrar) {
			return ((BeanDefinitionRegistrar)beanFactory).getBeanDefinition();
		}
		return new HashMap<>();
	}

	@Override
	public Object getBean(String beanName) {
		return beanFactory.getBean(beanName);
	}

	@Override
	public void registrarBean(String beanName, Object bean) {
       beanFactory.registrarBean(beanName,bean);
	}

	@Override
	public Object getBean(Class<?> typeClass) {
		return beanFactory.getBean(typeClass);
	}

	@Override
	public Map<String, Object> getBeans(Class<?> typeClass) {
		return beanFactory.getBeans(typeClass);
	}
}
